package com.mrx.xfriendship.controller;

import com.mrx.commons.annotations.XLog;
import com.mrx.xfriendship.model.bo.RecoveryBO;
import com.mrx.xfriendship.model.dto.*;
import com.mrx.xfriendship.model.vo.*;
import com.mrx.xfriendship.service.IMinioService;
import com.mrx.xfriendship.service.IPostService;
import com.mrx.xfriendship.service.IUserDetailService;
import com.mrx.xfriendship.service.IUserService;
import com.mrx.xfriendship.util.SecurityUtil;
import org.apache.dubbo.config.annotation.DubboReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

/**
 * 用户相关接口
 *
 * @author : 肖康宁
 * @since : 2023-01-13 15:19
 **/
@RestController
@RequestMapping("/user")
@XLog(ignoreMethod = "heartbeat")
public class UserController {

    @DubboReference
    private IUserDetailService userDetailService;

    @DubboReference
    private IPostService postService;

    @DubboReference
    private IUserService userService;

    @Resource
    private IMinioService minioService;

    private static final Logger logger = LoggerFactory.getLogger(UserController.class);

    /**
     * 登录 接口
     *
     * @param t    获取验证码时使用的 随机数 key
     * @param code 验证码 内容
     * @param vo   登录表单
     */
    @PostMapping("/login")
    public Result<UserDTO> login(@RequestParam String t, @RequestParam String code, @RequestBody LoginUserVO vo) {
        return Result.success("登录成功", userService.login(t, code, vo));
    }

    /**
     * 登出 接口
     */
    @GetMapping("/logout")
    public Result<String> logout() {
        // 即使 token 失效的情况调用 logout 也得返回 success, 因为此时 redis 里已经没有有效 token 了
        // 效果和正常调用 logout 是一样的
        try {
            userService.logout(SecurityUtil.getCurrentUserName());
        } catch (Exception e) {
            logger.warn(e.getLocalizedMessage());
        }
        return Result.success("退出成功");
    }

    /**
     * 注册 接口
     *
     * @param t    获取验证码时使用的 随机数 key
     * @param code 验证码内容
     * @param vo   注册表单
     */
    @PostMapping("/register")
    public Result<String> register(HttpServletRequest req, @RequestParam String t, @RequestParam String code, @RequestBody RegisterUserVO vo) {
        userService.register(t, code, req.getRemoteAddr(), vo);
        return Result.success("注册成功");
    }

    /**
     * 获取用户详情
     *
     * @param id 用户 id
     */
    @GetMapping("/detail")
    public Result<UserDetailDTO> detail(@RequestParam Integer id) {
        return Result.success(userDetailService.getUserDetail(id));
    }

    /**
     * 获取指定用户的 帖子
     *
     * @param id 用户 id
     */
    @GetMapping("/postList")
    public Result<PageDTO<PostDTO>> postList(@RequestParam Integer id) {
        return Result.success(postService.listPostsByUserId(id));
    }

    /**
     * 获取当前登录的用户信息
     */
    @GetMapping("/info")
    public Result<UserInfoDTO> info() {
        return Result.success(userService.userInfo(SecurityUtil.getCurrentUserId()));
    }

    /**
     * 上传用户头像
     *
     * @param file 头像文件
     */
    @PostMapping("/upload")
    public Result<String> upload(@RequestParam("file") MultipartFile file) {
        return Result.success("头像上传成功", minioService.preview(userService.updateAvatar(SecurityUtil.getCurrentUserId(), minioService.upload(file))));
    }

    /**
     * 上传 照片墙
     *
     * @param file 照片文件
     */
    @PostMapping("/uploadPhotoWall")
    public Result<String> uploadPhotoWall(@RequestParam("file") MultipartFile file) {
        String upload = minioService.upload(file);
        String fileName = userService.updatePhotoWall(SecurityUtil.getCurrentUserId(), upload);
        return Result.success("照片上传成功", minioService.preview(fileName));
    }

    /**
     * 删除 照片墙 中指定 id 的照片
     *
     * @param id 照片 id
     */
    @GetMapping("/deletePhotoWall")
    public Result<String> deletePhotoWall(@RequestParam Integer id) {
        userService.deletePhotoWall(SecurityUtil.getCurrentUserId(), id);
        return Result.success("照片删除成功");
    }

    /**
     * 更新 照片描述
     */
    @PostMapping("/updatePhotoDesc")
    public Result<String> updatePhotoDesc(@RequestBody PhotoWallVO vo) {
        userService.updatePhotoDesc(SecurityUtil.getCurrentUserId(), vo);
        return Result.success("照片描述更新成功");
    }

    /**
     * 更新当前登录的用户信息
     *
     * @param info 新的用户信息
     */
    @PostMapping("/updateInfo")
    public Result<String> updateInfo(@RequestBody UserInfoVO info) {
        userService.updateInfo(SecurityUtil.getCurrentUserId(), info);
        return Result.success("资料更新成功");
    }

    /**
     * 更新 当前登录的用户 密码
     *
     * @param info 用户信息
     */
    @PostMapping("/updatePassword")
    public Result<String> updatePassword(@RequestBody UserInfoVO info) {
        userService.updatePassword(SecurityUtil.getCurrentUserId(), info);
        return Result.success("密码修改成功");
    }

    /**
     * 发起 两步验证 绑定
     */
    @GetMapping("/req2faCode")
    public Result<String> req2faCode() {
        return Result.success("操作成功", userService.req2faCode(SecurityUtil.getCurrentUserName(), SecurityUtil.getCurrentUserId()));
    }

    /**
     * 使用 两步验证密码 登录
     *
     * @param userName 用户名
     * @param code     两步验证 的验证码
     */
    @GetMapping("/loginBy2faCode")
    public Result<UserDTO> loginBy2faCode(@RequestParam String userName, @RequestParam String code) {
        return Result.success("登录成功", userService.verify2faCode(userName, code));
    }

    /**
     * 发起签到
     */
    @GetMapping("/signing")
    public Result<String> signing() {
        userService.signing(SecurityUtil.getCurrentUserId());
        return Result.success("签到成功");
    }

    /**
     * 发起心跳
     */
    @GetMapping("/heartBeat")
    public Result<String> heartbeat() {
        userService.heartbeat(SecurityUtil.getCurrentUserId());
        return Result.success();
    }

    /**
     * 获取 当前在线用户 数量
     */
    @Deprecated
    @GetMapping("/onlineUsers")
    public Result<Integer> onlineUsers() {
        return Result.success(userService.onlineUserNumber());
    }

    /**
     * 获取 积分排行榜 接口
     *
     * @param pageVO 分页参数
     */
    @GetMapping("/scoreRank")
    public Result<ScoreRankPageDTO> scoreRank(PageVO pageVO) {
        PageDTO<ScoreRankDTO> pageDTO = userService.scoreRank(pageVO);
        ScoreRankPageDTO scoreRankPageDTO = new ScoreRankPageDTO();
        BeanUtils.copyProperties(pageDTO, scoreRankPageDTO);
        scoreRankPageDTO.setMe(userService.myScoreRank(SecurityUtil.getCurrentUserId()));
        return Result.success(scoreRankPageDTO);
    }

    /**
     * 获取 帖子排行榜 接口
     *
     * @param pageVO 分页参数
     */
    @GetMapping("/postRank")
    public Result<PostRankPageDTO> postRank(PageVO pageVO) {
        PageDTO<PostRankDTO> postRankDTOPageDTO = userService.postRank(pageVO);
        PostRankPageDTO pageDTO = new PostRankPageDTO();
        BeanUtils.copyProperties(postRankDTOPageDTO, pageDTO);
        pageDTO.setMe(userService.myPostRank(SecurityUtil.getCurrentUserId()));
        return Result.success(pageDTO);
    }

    /**
     * 通过 旧密码 找回密码 接口
     *
     * @param vo 找回密码 参数
     */
    @PostMapping("/recovery")
    public Result<?> recovery(@RequestBody RecoveryVO vo) {
        userService.recovery(RecoveryBO.of(vo, SecurityUtil.getCurrentUserId()));
        return Result.success();
    }

}
